home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 011 / packdir.aqm / packdir.asm
Assembly Source File  |  1985-11-22  |  20KB  |  484 lines

  1.            PAGE
  2.            PAGE 72,132
  3. TITLE      Program PACKDIR
  4.  
  5.            COMMENT "                       by Ted Mirecki
  6.  
  7.            Reads a sub-directory as a file, packs entries into
  8.            adjacent locations, eliminating deleted entries, and
  9.            deallocates empty sub-directory clusters.
  10. "
  11.  
  12. COM        GROUP   CODE,DATA
  13.            ASSUME  CS:COM, DS:COM, ES:COM, SS:COM
  14.  
  15. ;**********************************************************************
  16. ;
  17. ;    STRUCTURES
  18. ;
  19. ;**********************************************************************
  20.  
  21. ; Layout of a directory entry.
  22.  
  23. DIRENT     STRUC
  24. DNAME      DB      8 DUP(?)       ;NAME OF FILE
  25. DEXT       DB      ?,?,?          ;EXTENSION
  26. ATTR       DB      ?              ;ATTRIBUTE BYTE
  27.            DB      10 DUP(?)      ;RESERVED FOR DOS
  28. DTIME      DW      ?              ;FILE UPDATE TIME
  29. DDATE      DW      ?              ;FILE UPDATE DATE
  30. STARTCL    DW      ?              ;STARTING CLUSTER
  31. DSIZE      DD      ?              ;FILE SIZE, DOUBLE WORD
  32. DIRENT     ENDS
  33.  
  34.  
  35. ; Layout of a normal FCB
  36.  
  37. NORMFCB    STRUC
  38. DRIVE      DB      ?              ;DRIVE ID
  39. FNAME      DB      8 DUP(?)       ;FILE NAME
  40. FEXT       DB      ?,?,?          ;FILENAME EXTENSION
  41. CURBLOK    DW      ?              ;CURRENT BLOCK
  42. RECSIZE    DW      ?              ;RECORD SIZE FOR EACH READ
  43. FSIZELO    DW      ?              ;LO-ORDER WORD OF FILE SIZE
  44. FSIZEHI    DW      0              ;HI ORDER WORD OF FILE SIZE
  45. FDATE      DW      ?              ;DATE OF LAST UPDATE
  46.            DB      10 DUP(?)      ;RESERVED FOR DOS
  47. RECINBLOK  DB      ?              ;RECORD WITHIN BLOCK
  48. RELREC     DW      ?              ;DOUBLE-WORD RELATIVE RECORD NO.
  49.            DW      ?
  50. NORMFCB    ENDS
  51.  
  52. ;**********************************************************************
  53. ;
  54. ;    DATA SEGMENT
  55. ;
  56. ;**********************************************************************
  57.  
  58. DATA       SEGMENT BYTE 'COM'
  59.  
  60. ; Extended FCB No. 1 will be built from command line parameters passed
  61. ;   by DOS, and used to look up the sub-directory in its parent.
  62.  
  63. XFCB1      DB      0FFH,0,0,0,0,0 ;FCB EXTENSION HEADER
  64.            DB      10H            ;ATTR BYTE FOR SUB-DIRS
  65. FCB1       NORMFCB<>              ;NORMAL FCB FOLLOWS EXTENSION
  66.  
  67. ; Extended FCB No. 2 will be built by DOS as a result of lookup in
  68. ;   parent directory, and used open & read sub-directory file.
  69.  
  70. XFCB2      DB      0FFH,0,0,0,0,0,10H
  71. FCB2       NORMFCB<>
  72.  
  73.  
  74. ; Message strings
  75.  
  76. DISKERR$   DB      0DH,0AH,'Disk read error',0DH,0AH,'$'
  77. BADFAT$    DB      0DH,0AH,'FAT error: cluster chain not terminated'
  78. CRLF$      DB      0DH,0AH,'$'
  79. COUNT$     DB      ' had'
  80. INREC$     DB      6 DUP(' ')     ;SPACE FOR INPUT REC COUNT DIGITS
  81.            DB      ' clusters, now has'
  82. OUTREC$    DB      6 DUP(' ')     ;SPACE FOR OUTPUT COUNT DIGITS
  83.            DB      0DH,0AH,'$'
  84. ENDMSG$    DB      0DH,0AH
  85. NDIR$      DB      6 DUP(' ')     ;SPACE FOR DIRECTORY COUNT DIGITS
  86.            DB      ' Sub-Directories processed',0DH,0AH
  87. FREED$     DB      6 DUP(' ')     ;SPACE FOR FREED COUNT DIGITS
  88.            DB      ' clusters freed',0DH,0AH,'$'
  89.  
  90.  
  91. ; Miscellaneous data values
  92.  
  93. FCODE      DB      11H            ;FUNCTION CODE FOR FIND FIRST
  94. FILECLUS   DW      0              ;FILE SIZE FROM TRACING CLUSTER CHAIN
  95. FATCOUNT   DW      ?              ;NUMBER OF ENTRIES IN FAT
  96. CLUSLEN    DW      ?              ;BYTES PER CLUSTER
  97. SAVSTART   DW      ?              ;SAVE STARTING CLUSTER OF FILE
  98. SECSPER    DB      ?              ;SECTORS PER CLUSTER
  99. RETRY      DB      3              ;3 RETRIES IF READ ERROR
  100. INREC      DW      0              ;CURRENT INPUT RECORD NO.
  101. OUTREC     DW      0              ;CURRENT OUTPUT RECORD NO
  102. NDIRS      DW      0              ;COUNT OF DIRECTORIES PROCESSED
  103. FREED      DW      0              ;COUNT OF CLUSTERS FREED
  104.  
  105.  
  106. ; Open-ended buffer for holding File Allocation Table
  107.  
  108. FATWORD    LABEL   WORD           ;PROCESS FAT BY WORDS
  109.  
  110. DATA       ENDS
  111.  
  112.  
  113. ;**********************************************************************
  114. ;
  115. ;   CODE   SEGMENT
  116. ;
  117. ;**********************************************************************
  118.  
  119. CODE       SEGMENT BYTE PUBLIC 'COM'
  120.  
  121.            ORG     80H            ;PARAMATER AREA IN PSP
  122. SUBDATA    LABEL   BYTE           ;USE AS BUFFER FOR 1 SUBDIR ENTRY
  123.  
  124.            ORG     100H           ;CODE ORIGIN FOR COM PROGRAMS
  125. PACKDIR    PROC    FAR
  126.  
  127.  
  128. ;**********************************************************************
  129. ;   MAINLINE
  130. ;**********************************************************************
  131. ; Each called routine returns carry flag clear if no errors,
  132. ;   set if error.  If error, then DX points to error message.
  133. ;   Display the message, then exit to DOS.
  134.  
  135.            CALL    GETNAME        ;LOOK FOR FILENAME ON COMMAND LINE
  136.            CALL    FATREAD        ;READ IN THE FAT
  137.            JC      MSG
  138. NEXTNAM:   CALL    OPEN           ;LOOK UP FILENAME & OPEN IT
  139.            JC      EOJ            ;ALL DONE WHEN NO MORE MATCHING NAMES
  140.            CALL    DIRSIZE        ;GET FILE SIZE BY TRACING CLUSTERS
  141.            JC      MSG
  142.            CALL    PROCESS        ;PROCESS THE CONTENTS OF THE SUB-DIR
  143.            CALL    CLOSE          ;CLOSE THE SUB-DIR FILE
  144.            JMP     NEXTNAM
  145.  
  146. EOJ:       MOV     AX,NDIRS       ;CONVERT DIR COUNT TO ASCII
  147.            MOV     SI,OFFSET COM:NDIR$
  148.            CALL    I2ASC
  149.            MOV     AX,FREED       ;CONVERT FREED COUNT
  150.            MOV     SI,OFFSET COM:FREED$
  151.            CALL    I2ASC
  152.            MOV     DX,OFFSET COM:ENDMSG$
  153. MSG:       MOV     AH,9           ;FUNCTION 9 = DISPLAY STRING
  154.            INT     21H            ;CALL DOS TO DISPLAY MESSAGE
  155.            INT     20H            ;RETURN TO DOS
  156. PACKDIR    ENDP
  157.  
  158.  
  159. ;**********************************************************************
  160. ;    PROCEDURE GETNAME
  161. ;**********************************************************************
  162. ; Test if filename was specified on command line.  If not, build one
  163. ;   consisting of all wild characters.  Move name to FCB1, set DTA.
  164.  
  165. GETNAME    PROC    NEAR
  166.            MOV     SI,5CH              ;POINT TO 1ST FCB IN PREFIX
  167.            CMP     BYTE PTR [SI+1],' ' ;TEST FOR NAME FROM CMD LINE
  168.            JNE     GET1                ;NAME IS THERE
  169.            MOV     CX,11               ;ELSE INSERT 11 WILD CHARS
  170.            LEA     DI,[SI+1]           ;INTO NAME FLD OF FCB1
  171.            MOV     AL,'?'
  172.            REP     STOSB
  173.  
  174. GET1:      MOV     DI,OFFSET COM:FCB1  ;POINT TO FCB NO. 1
  175.            MOV     CX,12               ;CX = LENGTH OF DRIVE, NAME & EXT
  176.            REP     MOVSB               ;MOVE NAME FROM PREFIX TO FCB 1
  177.            RET
  178. GETNAME    ENDP
  179.  
  180.  
  181. ;**********************************************************************
  182. ;    PROCEDURE FATREAD
  183. ;**********************************************************************
  184. ; Get the FAT characteristics, calculate the size of the FAT, and read
  185. ; the FAT into the buffer.  If read error, reset disk & retry 3 times.
  186.  
  187. FATREAD    PROC    NEAR
  188.            MOV     DL,FCB2.DRIVE  ;MOVE DRIVE ID INTO DL
  189.            PUSH    DS             ;SAVE THE DATA SEGMENT
  190.            MOV     AH,1CH         ;FUNCTION 1C = GET FAT INFO
  191.            INT     21H            ;CALL DOS
  192.            POP     DS             ;RESTORE DATA SEGMENT
  193.            MOV     SECSPER,AL     ;SAVE SECTORS PER CLUSTER
  194.            MOV     FATCOUNT,DX    ;SAVE NUMBER OF FAT ENTRIES
  195.            CBW                    ;CONVERT SECS PER CLUS TO WORD
  196.            MUL     CX             ;AX=AX*CX, BYTES PER CLUSTER
  197.            MOV     CLUSLEN,AX     ;STORE IT FOR FUTURE USE
  198.            MOV     AX,FATCOUNT    ;RESTORE ENTRY COUNT IN AX
  199.            MOV     DX,AX          ;REPEAT IT IN DX
  200.            INC     DX             ;ADD 1 TO ROUND UP
  201.            SHR     DX,1           ;ENTRY COUNT DIVIDED BY 2
  202.            ADD     AX,DX          ;SIZE IN BYTES = 1.5 * ENTRY COUNT
  203.            ADD     AX,CX          ;ROUND UP TO NEXT SECTOR
  204.            DEC     AX             ;  BY ADDING SECTOR SIZE LESS 1
  205.            CWD                    ;CONVERT TO DBL WORD IN DX:AX
  206.            DIV     CX             ;AX / CX = FAT LENGTH IN SECTORS
  207.            MOV     CX,AX          ;MOVE SECTOR COUNT TO CX
  208.  
  209.            MOV     AH,19H         ;DETERMINE DEFAULT DRIVE
  210.            INT     21H            ;RETURNS DRIVE ID IN AL
  211.            MOV     DX,1           ;BEGIN AT SECTOR 1
  212.            MOV     BX,OFFSET COM:FATWORD   ;POINT TO BUFFER FOR FAT
  213. F1:        PUSH    AX             ;SAVE THE REGS,
  214.            PUSH    BX             ;   BECAUSE INT 25
  215.            PUSH    CX             ;   DESTROYS THEM
  216.            PUSH    DX
  217.            INT     25H            ;ABSOLUTE DISK READ
  218.            POP     DX             ;RESTORE REGS EXCEPT AX
  219.            POP     CX
  220.            POP     BX
  221.            JNC     F2             ;JUMP IF NO DISK ERRORS
  222.            POPF                   ;POP FLAGS SAVED BY INT 25
  223.            SUB     AH,AH          ;AH=0 IS DISK RESET FUNCTION
  224.            INT     13H            ;DISK I/O INTERRUPT
  225.            POP     AX             ;RESTORE SECTOR COUNT
  226.            DEC     RETRY          ;DECREMENT RETRY COUNT
  227.            JNZ     F1             ;TRY READING AGAIN IF NOT ZERO
  228.            MOV     DX,OFFSET COM:DISKERR$  ;ERROR EXIT
  229.            STC
  230.            RET
  231.  
  232. F2:        POPF                   ;READ OK: RESTORE STACK
  233.            POP     AX
  234.            CLC
  235.            RET
  236. FATREAD    ENDP
  237.  
  238.  
  239. ;**********************************************************************
  240. ;    PROCEDURE OPEN - find sub-dir name & open it as a data file
  241. ;**********************************************************************
  242. ; Input: AH is 11 to find first name, 12 to find subsequent.
  243. ;   If found, but not a sub-directory, look for next matching entry,
  244. ;   until a matching sub-directory is found or there are no more
  245. ;   matching entries.  If no match, exit with carry flag on,
  246. ;   else open the file, save starting cluster pointer,
  247. ;   display its name & turn carry flag off.
  248.  
  249. OPEN       PROC    NEAR
  250.            MOV     DX,OFFSET COM:XFCB2 ;SET DTA AT EXTENDED FCB 2
  251.            MOV     AH,1AH              ;FUNCTION 1A = SET DTA
  252.            INT     21H                 ;CALL DOS TO SET DTA
  253.            MOV     DX,OFFSET COM:XFCB1 ;POINT TO EXTENDED FCB NO. 1
  254.  
  255. OP1:       MOV     AH,FCODE            ;GET CODE 11 OR 12
  256.            INT     21H                 ;CALL DOS TO FIND FIRST/NEXT
  257.            CMP     AL,0FFH             ;AL=FF IF NOT FOUND
  258.            JNE     OP2                 ;SKIP IF FOUND
  259.            STC                         ;SET CARRY FLAG IF NOT FOUND
  260.            RET
  261.  
  262. OP2:       MOV     FCODE,12H                ;CODE 12 = FIND NEXT
  263.            CMP     BYTE PTR FCB2+1.ATTR,10H ;IF FOUND, TEST IF A SUB-DIR
  264.            JNE     OP1                      ;IF NOT, GO FIND NEXT ENTRY
  265.            CMP     BYTE PTR FCB2+1.DNAME,'.';IF SUB-DIR, TEST IF PERIOD
  266.            JE      OP1                      ;IF SO, GO FIND NEXT ENTRY
  267.  
  268.            MOV     AX,FCB2+1.STARTCL   ;GET STARTING CLUSTER FROM FCB
  269.            MOV     SAVSTART,AX         ;SAVE IT FOR FUTURE USE
  270.            MOV     DX,OFFSET COM:XFCB2 ;POINT TO EXTENDED FCB
  271.            MOV     AH,0FH              ;OPEN FILE FUNCTION
  272.            INT     21H
  273.            MOV     SI,OFFSET COM:FCB2.FNAME ;POINT TO NAME IN OPEN FCB
  274.            MOV     CX,11               ;DISPLAY 11 CHARS OF FILENAME
  275.            MOV     AH,2                ;DISPLAY CHARACTER FUNCTION
  276.  
  277. OP3:       MOV     DL,[SI]             ;GET FILENAME CHARACTER
  278.            INT     21H                 ;DISPLAY IT
  279.            INC     SI                  ;POINT TO NEXT CHAR IN NAME
  280.            LOOP    OP3
  281.  
  282.            CLC                         ;INDICATE NO ERRORS
  283.            RET
  284. OPEN       ENDP
  285.  
  286.  
  287. ;**********************************************************************
  288. ;    PROCEDURE DIRSIZE
  289. ;**********************************************************************
  290. ; Trace thru FAT, counting clusters in allocation chain.
  291. ;   For each cluster, add bytes per cluster to file size.
  292. ;   At exit, file size in bytes is stored in open FCB, file size
  293. ;   in clusters in location FILECLUS.
  294. ;   Register usage:  DX:AX is dword accumulator for file size
  295. ;                    BX is last cluster number
  296. ;                    CX contains count of FAT entries
  297. ;                    SI points to next FAT entry
  298. ;                    DI contains bytes per cluster
  299.  
  300. DIRSIZE    PROC    NEAR
  301.            MOV     BX,SAVSTART    ;PUT STARTING CLUSTER IN BX
  302.            MOV     DI,CLUSLEN     ;BYTES PER CLUSTER IN DI
  303.            MOV     CX,FATCOUNT    ;LOOP COUNT IN CX
  304.            SUB     AX,AX          ;ZERO OUT FILE SIZE
  305.            MOV     DX,AX          ;AND CLUSTER COUNT
  306.            MOV     FILECLUS,AX    ;AND CLUSTER COUNT
  307.  
  308. D1:        ADD     AX,DI          ;UPDATE FILE LENGTH
  309.            ADC     DX,0           ;CARRY INTO HI WORD
  310.            INC     FILECLUS       ;UPDATE CLUSTER COUNT
  311.            MOV     SI,BX          ;CALC BX*1.5 IN SI
  312.            SHR     BX,1
  313.            PUSHF                  ;SAVE THE CARRY FLAG
  314.            ADD     SI,BX
  315.            MOV     BX,FATWORD[SI] ;GET NEXT FAT ENTRY
  316.            POPF                   ;RESTORE CARRY FROM SHIFT
  317.            JNC     D2             ;SKIP IF BX WAS EVEN
  318.            SHR     BX,1           ;IF ODD, RIGHT-JUST
  319.            SHR     BX,1           ;  HI 12 BITS OF CLUSTER NO.
  320.            SHR     BX,1
  321.            SHR     BX,1
  322. D2:        AND     BX,0FFFH       ;ZERO OUT 4 HI BITS
  323.            CMP     BX,0FF8H       ;TEST FOR END OF CHAIN
  324.            JGE     D3             ;END IF CLUSTER IS FF8 OR ABOVE
  325.            LOOP    D1             ;LOOP IF NOT
  326.  
  327.            MOV     DX,OFFSET COM:BADFAT$    ;IF FAT END BUT NOT CHAIN END,
  328.            STC                              ;    THEN ERROR
  329.            RET
  330.  
  331. D3:        MOV     FCB2.FSIZELO,AX     ;PUT FILE LENGTH INTO FCB
  332.            MOV     FCB2.FSIZEHI,DX
  333.            CLC                         ;CLEAR ERROR FLAG
  334.            RET
  335. DIRSIZE    ENDP
  336.  
  337.  
  338. ;**********************************************************************
  339. ;    PROCEDURE PROCESS
  340. ;**********************************************************************
  341. ; Read the sub-directory as a data file, 1 entry at a time.
  342. ;   Write out entries ehich are not deleted.  At first unused entry,
  343. ;   write a zero-filled entry and truncate the file to that length.
  344. ;   Regs:  SI points to I/O buffer.
  345.  
  346. PROCESS    PROC    NEAR
  347.        SUB       AX,AX
  348.        MOV       INREC,AX
  349.        MOV       OUTREC,AX
  350.            MOV     SI,OFFSET COM:SUBDATA;POINT TO I/O BUFFER
  351.            MOV     DX,SI                ;SET DTA TO BUFFER
  352.            MOV     AH,1AH
  353.            INT     21H
  354.            MOV     FCB2.RECSIZE,32     ;INSERT REC SIZE INTO FCB
  355.            MOV     DX,OFFSET COM:XFCB2 ;POINT TO EXTENDED FCB
  356.  
  357. READ:      MOV     AX,INREC       ;GET RECORD (ENTRY) NO. TO READ
  358.            MOV     FCB2.RELREC,AX ;PUT IT INTO FCB'S RELATIVE REC FLD
  359.            INC     INREC          ;UPDATE RECORD NO. FOR NEXT READ
  360.            MOV     AH,21H         ;PERFORM DIRECT ACCESS READ
  361.            INT     21H
  362.            TEST    AL,AL          ;EOF IF AL NOT ZERO
  363.            JNZ     EOF
  364.  
  365.            CMP     BYTE PTR SUBDATA,0E5H    ;IS ENTRY DELETED?
  366.            JE      READ           ;YES: DO NOT WRITE, GO READ NEXT
  367.  
  368. WRITE:     MOV     AX,OUTREC      ;GET RECORD NO. TO WRITE
  369.            MOV     FCB2.RELREC,AX ;PUT IT INTO FCB
  370.            INC     OUTREC         ;UPDATE REC NO. FOR NEXT READ
  371.            MOV     AH,22H         ;PERFORM DIRECT ACCESS WRITE
  372.            INT     21H
  373.            CMP     BYTE PTR SUBDATA,0 ;NEVER-USED ENTRY?
  374.            JNE     READ           ;IF NOT, READ NEXT, ELSE EOF
  375.  
  376. EOF:       RET                    ;RETURN AT END OF DATA
  377. PROCESS    ENDP
  378.  
  379.  
  380. ;**********************************************************************
  381. ;   PROCEDURE CLOSE: Close the sub-dir file, display counts
  382. ;**********************************************************************
  383. CLOSE      PROC    NEAR
  384.            MOV     AX,OUTREC      ;GET COUNT OF ENTIRES WRITTEN
  385.            TEST    AX,AX          ;MAKE SURE SOME WERE WRITTEN
  386.            JZ      CL1
  387.            MOV     FCB2.RELREC,AX ;SET RECORD COUNT IN FCB
  388.            SUB     CX,CX          ;WRITE NOTHING, JUST SET SIZE
  389.            MOV     DX,OFFSET COM:XFCB2 ;POINT TO EXTENDED FCB
  390.            MOV     AH,28H         ;PERFORM BLOCK WRITE, SET SIZE
  391.            INT     21H
  392.  
  393. CL1:       MOV     AX,FILECLUS    ;GET INPUT CLUSTER COUNT
  394.            ADD     FREED,AX       ;UPDATE FREED CLUSTER COUNT
  395.            MOV     SI,OFFSET COM:INREC$
  396.            CALL    I2ASC          ;CONVERT COUNT TO ASCII DIGITS
  397.  
  398.            MOV     AX,OUTREC      ;GET OUTPUT RECORD COUNT
  399.            MOV     BX,32          ;BYTES PER ENTRY
  400.            MUL     BX             ;DX:AX = OUTPUT BYTES
  401.            DIV     CLUSLEN        ;GET OUTPUT CLUSTERS, REMDR IN DX
  402.            TEST    DX,DX          ;TEST FOR REMAINDER
  403.            JZ      CL2
  404.            INC     AX             ;IF REMDR, ROUND UP TO NEXT CLUSTER
  405. CL2:       SUB     FREED,AX       ;TOTAL FREED = FREED + INPUT - OUTPUT
  406.            MOV     SI,OFFSET COM:OUTREC$
  407.            CALL    I2ASC          ;CONVERT OUTPUT COUNT TO DIGITS
  408.            MOV     DX,OFFSET COM:COUNT$     ;DISPLAY COUNT MSG
  409.            MOV     AH,9
  410.            INT     21H
  411.            INC     NDIRS          ;INCREMENT DIRECTORY COUNT
  412.            RET
  413. CLOSE      ENDP
  414. CODE       ENDS
  415.  
  416.  
  417. COMMENT " **************************************************************
  418.  MODULE I2ASC CONVERTS 2-BYTE INTEGER INTO 6-BYTE NUMERIC ASCII STRING
  419.      INPUT:  NUMBER TO BE CONVERTED IN AX
  420.              DS:SI POINTS TO STRING TO RECEIVE OUTPUT
  421.      OUTPUT: STRING AT DS:SI, RIGHT JUSTIFIED, BLANK PADDED
  422.                   IF AX=0, STRING IS 1 ZERO IN RIGHTMOST POSITION
  423.                   IF AX<0, LEADING MINUS IS FLOATED BEFORE 1ST DIGIT
  424.              DS:DI POINTS TO FIRST NON-BLANK IN STRING
  425.              ALL OTHER REGISTERS UNCHANGED
  426. ************************************************************************
  427. "
  428. CODE       SEGMENT BYTE PUBLIC 'COM'
  429.            ASSUME  CS:COM
  430. I2ASC      PROC    NEAR
  431.            PUBLIC  I2ASC
  432.  
  433.            PUSH    ES             ;SAVE REGISTERS
  434.            PUSH    DX
  435.            PUSH    CX
  436.            PUSH    BX
  437.            PUSH    AX
  438.  
  439.            MOV     AL,' '         ;BLANK OUT STRING
  440.            MOV     DX,DS
  441.            MOV     ES,DX
  442.            MOV     DI,SI
  443.            CLD
  444.            MOV     CX,6
  445.            REP STOSB
  446.  
  447.            MOV     DI,SI
  448.            ADD     DI,5           ;POINT AT STRING END
  449.            MOV     BX,10          ;BASE TEN DIVISOR
  450.            POP     AX             ;GET BINARY NUMBER INTO AX
  451.            PUSH    AX
  452.            STD                    ;MOVE BACKWARDS THRU STRING
  453.  
  454. DIVLOOP:   CWD                    ;CONVERT TO DBL WORD IN DX,AX
  455.            IDIV    BX             ;QUOTIENT IN AX, REMAINDER IN DX
  456.            TEST    DL,80H         ;TEST IF REMAINDER NEGATIVE
  457.            JZ      $+4            ;SKIP IF POS
  458.            NEG     DL             ;ELSE GET ABS OF REM
  459.            OR      DX,30H         ;INSERT ASCII ZONE
  460.            XCHG    AX,DX          ;EXCHANGE QUOT & REM
  461.            STOSB                  ;STORE ASCII CHAR IN STRING
  462.            MOV     AX,DX          ;RESTORE QUOTIENT
  463.            TEST    AX,0FFFFH      ;TEST IF MORE DEC DIGITS
  464.            JNZ     DIVLOOP
  465.  
  466.            POP     BX             ;RESTORE INTEGER INTO BX
  467.            TEST    BX,8000H       ;TEST IF NUMBER NEG
  468.            JZ      I2EXIT
  469.            MOV     AL,'-'         ;INSERT MINUS SIGN IF NEG
  470.            STOSB
  471.  
  472. I2EXIT:    INC     DI             ;POINT AT LAST NON-BLANK
  473.            MOV     AX,BX          ;RESTORE REGS
  474.            POP     BX
  475.            POP     CX
  476.            POP     DX
  477.            POP     ES
  478.            CLD
  479.            RET
  480. I2ASC      ENDP
  481.  
  482. CODE       ENDS
  483.            END     PACKDIR
  484.